﻿using Autodesk.Revit.DB;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CoreDB.Extensions
{
    /// <summary>
    /// 这里的Solid指代继承了GeomertyObject（除Mesh外）的所有子类，虽然他与Curve等平级，但是通过Solid可以轻松取到他们，所以为了方便，把他们都写在一起
    /// </summary>
    public static class SolidExtension
    {
        private const double defaultEps = 1e-3;
        /// <summary>
        /// 获取GeometryObject中所有的 Solid
        /// </summary>
        /// <param name="gObj"></param>
        /// <returns></returns>
        public static List<Solid> GetSolids(this GeometryObject gObj)
        {
            List<Solid> solids = new List<Solid>();
            if (gObj is Solid solid) // already solid
            {
                if (solid.Faces.Size > 0 && Math.Abs(solid.Volume) > 0) // some solid may have not any face?!
                    solids.Add(solid);
            }
            else if (gObj is GeometryInstance gIns) // find solids from GeometryInstance
            {
                IEnumerator<GeometryObject> gIter2 = gIns.GetInstanceGeometry().GetEnumerator();
                gIter2.Reset();
                while (gIter2.MoveNext())
                    solids.AddRange(GetSolids(gIter2.Current));
            }
            else if (gObj is GeometryElement gElem) // find solids from GeometryElement, this will not happen at all?
            {
                IEnumerator<GeometryObject> gIter2 = gElem.GetEnumerator();
                gIter2.Reset();
                while (gIter2.MoveNext())
                    solids.AddRange(GetSolids(gIter2.Current));
            }
            return solids;
        }
        /// <summary>
        /// Gets solid objects of specified element.
        /// </summary>
        /// <param name="elem">Element to retrieve solid geometry.</param>
        /// <param name="opt">geometry option.</param>
        /// <returns>Solids of the geometry.</returns>
        public static List<Solid> GetSolids(this Element elem, Options opt = null)
        {
            if (null == elem)
                return null;
            if (null == opt)
                opt = new Options() { DetailLevel = ViewDetailLevel.Fine };// 默认用精细视图
            List<Solid> solids = new List<Solid>();
            GeometryElement gElem = null;
            try
            {
                gElem = elem.get_Geometry(opt);
                if (null == gElem)
                    return solids;
                IEnumerator<GeometryObject> gIter = gElem.GetEnumerator();
                gIter.Reset();
                while (gIter.MoveNext())
                    solids.AddRange(GetSolids(gIter.Current));
            }
            catch { }
            return solids;
        }

        /// <summary>
        /// 获取Element 的faces
        /// </summary>
        /// <param name="elem"></param>
        /// <param name="opt"></param>
        /// <returns>The faces of the elements.</returns>
        public static List<Face> GetFaces(this Element elem, Options opt = null)
        {
            List<Solid> solids = elem.GetSolids(opt);
            List<Face> faces = new List<Face>();
            foreach (Solid solid in solids)
                foreach (Face face in solid.Faces)
                    faces.Add(face);
            return faces;
        }

        public static List<Face> GetFacesByNormal(this Element elem, XYZ normal, double eps = defaultEps, Options opt = null)
        {
            var tempFaces = elem.GetFaces();
            if (tempFaces.Count > 0)
                tempFaces = tempFaces.FindAll(x => x.ComputeNormal(new UV(0.5, 0.5)).IsEqual(normal, eps));
            return tempFaces;
        }




    }
}
